<?php
namespace app\adminapiv3\service\module_manage\netfilter;

/**
 * @name: netfilter 服务
 * @Param: 
 * @Description: 
 * @Author: foo
 * @Date: 2019-10-31 10:32:55
 */
use app\common\exception\CustomException;
use app\adminapiv3\service\BaseService;
use app\common\database\AutoIncreMentService;
use app\common\definition\HostDefinition;
use app\common\definition\netfilter\FirewallRuleDefinition;
use app\common\definition\netfilter\NetfilterConfigDefinition;
use app\common\netfilter\Rule;
use app\common\service\module_manage\netfilter\HostLearnConfig;
use app\common\service\module_manage\netfilter\HostRule;
use think\Db;

class NetfilterService extends BaseService
{
    public $processed = false;//是否已经处理过(用户检测规则冲突)

    /**
     * @name: 处理输出
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-05 18:14:41
     */
    public function processOut ($childData)
    {
        $return = [];
        if (empty($childData))
        {
            return $return;
        }

        $childData = array_map(function($v){
            $v['alias'] = trim($v['alias'], ',');
            $v['dest_ip'] = IpProcessService::outProcess($v['dest_ip']);
            $v['src_ip'] = IpProcessService::outProcess($v['src_ip']);
            $v['src_port'] = PortProcessService::outProcess($v['src_port']);
            $v['dest_port'] = PortProcessService::outProcess($v['dest_port']);

            return $v;
        }, $childData);

        return $childData;
    }

    /**
     * @name: 检测规则是否冲突
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-14 17:53:03
     */
    private function checkRule ($data, $model, $fid)
    {
        $conflict_a = $return = [];
        $host_id_a = $this->CheckControlledFirewall();
        if (empty($host_id_a))
        {
            return $return;
        }

        foreach ($host_id_a as $host_id)
        {
            foreach ($data as $inputRule)
            {
                if($model->checkRule($host_id, $inputRule, $fid, $inputRule['protocols']) > 0 && $inputRule['force'] == 0)
                {
                    $conflict_a[] = $host_id;
                    break(1);
                }
            }
            
        }

        if(!empty($conflict_a))
        {
            throw new CustomException($this->hostErrorMessage($conflict_a, '规则冲突，请检查规则'), 499);
        }

        return $return;
    }

    /**
     * @name: 处理输入端口
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-05 14:59:22
     */
    public function processInput ($data, $model)
    {

        if($this->processed)
        {
            return $data;
        }

        $temp = [
            'protocols' => $data['protocols'],
            'direction' => $data['direction'],
            'type' => HostRule::TYPE_HANDLE,
            'process' => $data['process'],
            'force' => isset($data['force']) ? $data['force'] : 0,
        ];
        
        $ip_a = IpProcessService::inputProcess($data['src_ip'], $data['dest_ip']);
        $port_a  = PortProcessService::inputProcess($data['src_port'], $data['dest_port']);
        foreach ($ip_a as $ip)
        {
            foreach ($port_a as $port)
            {
                $return[] = array_merge($temp, $ip, $port);
            }
        }

        $fid = isset($data['fid']) ? $data['fid'] : 0 ; 
        $this->checkRule($return, $model, $fid);

        $this->processed = true;


        return $return;
    }

    /**
     * @name: 检测是否已经接管防火墙
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-12-24 15:02:37
     */
    public function CheckControlledFirewall ()
    {
        $host_id = $this->getHost('id');
        $HostLearnConfig = new HostLearnConfig();
        $host = $HostLearnConfig->selectByHostId($host_id, 'host_id,controlled_firewall');
        $uninited_host = $return = [];
        foreach ($host as $v)
        {
            if($v['controlled_firewall'] == NetfilterConfigDefinition::FIREWALL_CONTROLLED)
            {
                $return[] = $v['host_id'];
            }
            else
            {
                $uninited_host[] = $v['host_id'];
            }

        }
        
        if(!empty($uninited_host))
        {
            throw new CustomException($this->hostErrorMessage($uninited_host, '未接管防火墙,请重新选择主机!'), 422);
        }

        return $return;
    }

    /**
     * @name: 添加
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2019-11-20 11:23:24
     */
    public function add ($insertData, $alias, $server, $scope)
    {
        $host_id_a = $this->CheckControlledFirewall();
        $return = [];
        foreach ($host_id_a as $host_id)
        {
            $fid = AutoIncreMentService::getTableAutoId('host_rule');
            $v = $insertData;
            $f_insert_v = array_shift($v);
            $f_insert_v['id'] = $fid;
            $f_insert_v['fid'] = $fid;
            $f_insert_v['host_id'] = $host_id;
            $f_insert_v['alias'] = $alias;
            $f_insert_v['scope'] = $scope;
            $server->firstAdd($f_insert_v);
            $child_a = array_map(function($cv) use ($fid, $host_id){
                $cv['host_id'] = $host_id;
                $cv['fid'] = $fid;
                return $cv;
            }, $v);

            $server->childAdd($child_a);//子规则
            $return[$host_id] = $fid;
        }

        return $return;
    }

    /**
     * @name: 添加真实防火墙规则
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-11-03 14:40:19
     */
    public function addRealFirewallRule ($data, $fid_a = [])
    {

        if (empty($data))
        {
            return ;
        }
        $host_a = $this->getHost();

        //检测是不是多条规则同时处理
        if(count($data) == count($data, COUNT_RECURSIVE))
        {
            $data_a = [$data];
        }
        else
        {
            $data_a = $data;
        }
        $Rule = new Rule();
        foreach ($host_a as $host_id => $host_data)
        {
            foreach ($data_a as $data)
            {
                if (!isset($data['mac_addr']))
                {
                    $data['mac_addr'] = '';
                    $data['have_mac_addr'] = '';
                }
                
                $data['status'] = FirewallRuleDefinition::RULE_ENABLE;
                
                $content = $Rule->firewallRule($data, $host_data['os']);
                foreach ($content as $v)
                {
                    $rule_id = isset($fid_a[$host_id]) ? $fid_a[$host_id] : $data['fid'];
                    $temp = [
                        'rule_id' => $rule_id,
                        'host_id' => $host_id,
                        'content' => $v,
                        'rank' => $rule_id,
                        'source' => FirewallRuleDefinition::HANDLE_RULE_SOURCE,
                    ];

                    if ($host_data['os'] == HostDefinition::WINDOWS_OPERATION_SYSTEM)
                    {
                        $temp['region'] = FirewallRuleDefinition::DEFAULT_NORMAL_RULE_REGION;
                    }
                    else
                    {
                        $temp['region'] = $data['scope'];
                    }
                    $firewall_a[] = $temp;
                }
            }
            
        }

        Db::name('netfilter_firewall_rule')->insertAll($firewall_a);

        foreach($host_a as $host_id => $host_data)
        {
            //只有linux 才涉及排序功能windows 不涉及
            if ($host_data['os'] == HostDefinition::LINUX_OPERATION_SYSTEM)
            {
                $SortRuleService = new SortRuleService();
                $SortRuleService->pushContentToFile($host_id);
            }
        }

        return $firewall_a;
    }


}